package com.zbkj.client.task;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.zbkj.client.config.ClientTokenComponent;
import com.zbkj.client.config.WebSocketSessionManager;
import com.zbkj.client.enums.WebSocketEventType;
import com.zbkj.client.service.AgentClientService;
import com.zbkj.client.service.ClientLoginService;
import com.zbkj.client.service.DigitalPersonService;
import com.zbkj.client.vo.DpVideoCjVo;
import com.zbkj.common.model.client.digital.DgVideo;
import com.zbkj.service.service.DgVideoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component
public class DpVideoStatusUpdateTask {
    @Resource
    private ThreadPoolTaskScheduler taskScheduler;
    @Resource
    private RestTemplate restTemplate;
    @Resource
    private DgVideoService dgVideoService;
    @Resource
    private DigitalPersonService digitalPersonService;
    @Autowired
    private DpVideoUrlUpdateTask dpVideoUrlUpdateTask;

    @Autowired
    private ClientLoginService clientLoginService;

    @Autowired
    private AgentClientService agentClientService;

    @Autowired
    private WebSocketSessionManager webSocketSessionManager;

    @Value("${digital-person.url}")
    private String digitalPersonUrl;


    private final String dpVideoDetailUrl = "/open/v1/video";
    private final ObjectMapper objectMapper = new ObjectMapper();

    public void start(String linkId) {
        schedule(linkId, 0, 3 * 60 * 1000); // 首次3分钟后执行
    }

    private void schedule(String linkId, int retryCount, long delay) {
        taskScheduler.schedule(() -> {
            try {
                doTask(linkId, retryCount);
            } catch (Exception e) {
                log.error("定时任务-合成视频定时任务异常", e);
            }
        }, new Date(System.currentTimeMillis() + delay));
    }

    private void doTask(String linkId, int retryCount) {
        DgVideo dgVideo = dgVideoService.lambdaQuery()
                .eq(DgVideo::getLinkId, linkId)
                .one();
        if (dgVideo == null) {
            log.warn("定时任务-未找到合成视频记录，linkId={}", linkId);
            return;
        }
        if (dgVideo.getIsDel() != null && dgVideo.getIsDel() == 1) {
            log.info("定时任务-合成视频已被删除，linkId={}", linkId);
            return;
        }
        if (dgVideo.getStatus() != null && dgVideo.getStatus() == 30) {
            //扣点
            clientLoginService.updateMerPoint(dgVideo.getUserId(),
                    dgVideo.getMerId(),
                    "addVideo",
                    dgVideo.getId(),
                    agentClientService.getMouleName("addVideo"),
                    "",
                    agentClientService.getPointByDuration("addVideo", dgVideo.getDuration()),
                    dgVideo.getDuration()
            );

            log.info("定时任务-合成视频已更新过，linkId={}", linkId);
            return;
        }

        // 拉取蝉镜接口
        String accessToken = digitalPersonService.getAccessToken();
        String url = digitalPersonUrl + dpVideoDetailUrl + "?id=" + linkId;
        HttpHeaders headers = new HttpHeaders();
        headers.set("access_token", accessToken);
        HttpEntity<Void> entity = new HttpEntity<>(headers);
        ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
        String body = response.getBody();
        if (body == null) {
            log.warn("定时任务-蝉镜返回空数据，linkId={}", linkId);
            return;
        }
        try {
            JsonNode root = objectMapper.readTree(body);
            int code = root.path("code").asInt();
            if (code != 0) {
                log.warn("定时任务-蝉镜返回code!=0，linkId={}, code={}, msg={}", linkId, code, root.path("msg").asText());
                if (retryCount < 5) {
                    log.info("合成视频未完成，1分钟后重试，linkId={}, retry={}", linkId, retryCount + 1);
                    schedule(linkId, retryCount + 1, 60 * 1000);
                }
                return;
            }
            JsonNode dataNode = root.path("data");
            if (dataNode.isMissingNode() || dataNode.isNull()) {
                log.warn("定时任务-蝉镜返回data字段为空，linkId={}", linkId);
                return;
            }
            DpVideoCjVo cjVo = objectMapper.treeToValue(dataNode, DpVideoCjVo.class);
            if (cjVo == null) {
                log.warn("定时任务-data字段转DpVideoCjVo失败，linkId={}", linkId);
                return;
            }

            if (cjVo.getStatus() != 10 && dgVideo.getStatus() == 10) {
                // 原有字段更新逻辑
                dgVideo.setVideoUrl(cjVo.getVideo_url());
                dgVideo.setSubtitleDataUrl(cjVo.getSubtitle_data_url());
                dgVideo.setPreviewUrl(cjVo.getPreview_url());
                dgVideo.setDuration(cjVo.getDuration());
                dgVideo.setStatus(cjVo.getStatus());
                dgVideo.setProgress(cjVo.getProgress());
                dgVideo.setMsg(cjVo.getMsg());
                dgVideo.setAudioUrls(cjVo.getAudio_urls());
                dgVideo.setUpdateTime(new Date());

                dgVideoService.updateById(dgVideo);
                log.info("定时任务-合成视频状态已更新，linkId={}", linkId);

                // 2. 事件名判断
                String eventName;

                // status=30时异步上传OSS
                if (cjVo.getStatus() != null && cjVo.getStatus() == 30) {
//                    eventName = "AddDpVideoSuccess";
                    eventName = WebSocketEventType.AddDpVideoSuccess.name();
                    // 异步上传OSS和更新数据库
                    dpVideoUrlUpdateTask.start(dgVideo, cjVo);

                    //扣点
                    clientLoginService.updateMerPoint(dgVideo.getUserId(),
                            dgVideo.getMerId(),
                            "addVideo",
                            dgVideo.getId(),
                            agentClientService.getMouleName("addVideo"),
                            "",
                            agentClientService.getPointByDuration("addVideo", dgVideo.getDuration()),
                            dgVideo.getDuration()
                    );

                } else {
//                    eventName = "AddDpVideoFail";
                    eventName = WebSocketEventType.AddDpVideoFail.name();
                }

                // 3. WebSocket事件推送
                Integer userId = dgVideo.getUserId();
                if (userId != null) {
                    Map<String, Object> data = new HashMap<>();
                    data.put("id", dgVideo.getId());
                    data.put("linkId", cjVo.getId());
                    data.put("status", cjVo.getStatus());

                    Map<String, Object> message = new HashMap<>();
                    message.put("event", eventName);
                    message.put("data", data);

                    String jsonMessage = JSON.toJSONString(message);
                    webSocketSessionManager.sendMessageToUser(userId, jsonMessage);
                    log.info("向用户 {} 推送数字人视频状态更新: {}", userId, jsonMessage);
                }

                return;
            }

            if (cjVo.getStatus() == 10 && dgVideo.getStatus() == 10 && retryCount < 5) {
                log.info("合成视频未完成，1分钟后重试，linkId={}, retry={}", linkId, retryCount + 1);
                schedule(linkId, retryCount + 1, 60 * 1000);
            }
        } catch (Exception e) {
            log.error("定时任务-解析蝉镜返回数据异常，linkId={}", linkId, e);
        }
    }
} 